Service Registration Process in ASP.NET Core and Dependency Injection
ASP.NET Core: सर्विस रजिस्ट्रेशन और डिपेंडेंसी इंजेक्शन
नमस्ते दोस्तों! 👋 आज हम ASP.NET Core की एक बहुत ही महत्वपूर्ण अवधारणा पर बात करेंगे - सर्विस रजिस्ट्रेशन (Service Registration) और डिपेंडेंसी इंजेक्शन (Dependency Injection - DI). यदि आप एक ASP.NET Core डेवलपर हैं, तो ये दोनों कॉन्सेप्ट आपके कोड को साफ, व्यवस्थित और टेस्ट करने योग्य बनाने के लिए बेहद ज़रूरी हैं.
इस पोस्ट में, हम जानेंगे कि:
- NET Core एप्लीकेशन में सर्विस रजिस्ट्रेशन की प्रक्रिया क्या होती है.
- डिपेंडेंसी इंजेक्शन (DI) कंटेनर क्या है और यह कैसे काम करता है.
- DI कंटेनर का उपयोग करने के मुख्य लाभ क्या हैं, जो आपके डेवलपमेंट वर्कफ़्लो को बेहतर बना सकते हैं.
- और यदि आप एक ही सर्विस को कई बार रजिस्टर करते हैं, तो क्या होता है - यानी एक ही सर्विस का पुनः रजिस्ट्रेशन.
तो चलिए, इस दिलचस्प यात्रा पर निकलते हैं और ASP.NET Core में मॉडर्न एप्लीकेशन डेवलपमेंट के इन बिल्डिंग ब्लॉक्स को समझते हैं!
सर्विस रजिस्ट्रेशन की प्रक्रिया
ASP.NET Core एप्लीकेशन के अंतर्गत सर्विस रजिस्ट्रेशन की प्रक्रिया को समझना एक मूलभूत जरूरत है इसको समझे बिना एप्लीकेशन निर्माण की कल्पना भी नहीं की जा सकती है अतः इसे समझना अति आवश्यक है आये इसे समझते हैं।
ASP.NET Core एप्लीकेशन में सर्विस रजिस्ट्रेशन (Service Registration) एक मूलभूत अवधारणा है, जो डिपेंडेंसी इंजेक्शन (Dependency Injection - DI) पैटर्न का दिल है। यह एप्लीकेशन के विभिन्न घटकों (कंपोनेंट्स) को एक-दूसरे पर कम निर्भर (loosely coupled) रखने और कोड को अधिक मॉड्यूलर, टेस्टेबल और मैनेजेबल बनाने में मदद करता है।
सर्विस रजिस्ट्रेशन की प्रक्रिया
सर्विस रजिस्ट्रेशन का मतलब है कि आप ASP.NET Core के डिपेंडेंसी इंजेक्शन (DI) कंटेनर को बताते हैं कि जब किसी विशिष्ट इंटरफ़ेस या क्लास की आवश्यकता हो, तो उसे कौन सी कंक्रीट इम्प्लीमेंटेशन प्रदान करनी है। यह आमतौर पर एप्लीकेशन के स्टार्टअप के दौरान किया जाता है, .NET 6+ में Program.cs फाइल में।
प्रक्रिया को समझने के लिए इन चरणों को देखें:
- सर्विसेज की पहचान: सबसे पहले, आप उन कंपोनेंट्स की पहचान करते हैं जिन्हें DI के माध्यम से इंजेक्ट करने की आवश्यकता होगी। ये अक्सर इंटरफेस और उनकी कंक्रीट क्लास इम्प्लीमेंटेशन होती हैं।
- उदाहरण: आपके पास एक इंटरफ़ेस IMyService हो सकता है और इसकी इम्प्लीमेंटेशन MyServiceImplementation।
- DI कंटेनर में रजिस्ट्रेशन: आप Services प्रॉपर्टी (जो IServiceCollection प्रकार की होती है) का उपयोग करके इन इंटरफेस और इम्प्लीमेंटेशन को DI कंटेनर में रजिस्टर करते हैं। रजिस्ट्रेशन के दौरान, आपको सर्विस के लाइफटाइम (Lifetime) को भी परिभाषित करना होता है। ASP.NET Core तीन मुख्य लाइफटाइम विकल्प प्रदान करता है:
- AddSingleton<TService, TImplementation>():
- जब पहली बार रिक्वेस्ट की जाती है तो सर्विस का केवल एक इंस्टेंस बनाया जाता है, और फिर वह इंस्टेंस एप्लीकेशन के पूरे लाइफटाइम के लिए पुन: उपयोग किया जाता है।
- इसका उपयोग लॉगिंग सर्विसेज़, कॉन्फ़िगरेशन सर्विसेज़ या अन्य ऐसी सर्विसेज़ के लिए किया जाता है जिनमें स्टेट नहीं होता या जो पूरे एप्लीकेशन में साझा की जाती हैं।
- AddScoped<TService, TImplementation>():
- प्रत्येक HTTP रिक्वेस्ट के दायरे (scope) में सर्विस का एक नया इंस्टेंस बनाया जाता है। इसका मतलब है कि एक ही HTTP रिक्वेस्ट के दौरान जितनी बार भी सर्विस की आवश्यकता होगी, उसी इंस्टेंस का उपयोग किया जाएगा।
- जब रिक्वेस्ट समाप्त होती है, तो इंस्टेंस को डिस्पोज कर दिया जाता है।
- इसका उपयोग डेटाबेस कॉन्टेक्स्ट या ऑपरेशन-स्पेसिफिक सर्विसेज़ के लिए किया जाता है जहाँ आपको यह सुनिश्चित करना होता है कि रिक्वेस्ट के भीतर सभी संबंधित ऑपरेशंस एक ही इंस्टेंस पर हों।
- AddTransient<TService, TImplementation>():
- जब भी सर्विस का अनुरोध किया जाता है तो सर्विस का एक नया इंस्टेंस बनाया जाता है।
- यह सबसे हल्का लाइफटाइम है और इसका उपयोग लाइटवेट, स्टेटलेस सर्विसेज़ के लिए किया जाता है जिन्हें हर बार उपयोग करने पर एक नए इंस्टेंस की आवश्यकता होती है।
- AddSingleton<TService, TImplementation>():
- सर्विस का रिजॉल्व होना (Resolution): जब NET Core को किसी कंट्रोलर, मिडलवेयर, या किसी अन्य सर्विस के कंस्ट्रक्टर में किसी रजिस्टर्ड सर्विस की आवश्यकता होती है, तो DI कंटेनर स्वचालित रूप से उस सर्विस का एक इंस्टेंस बनाता है (या एक मौजूदा इंस्टेंस प्रदान करता है, लाइफटाइम के आधार पर) और उसे इंजेक्ट करता है। आपको मैन्युअल रूप से new कीवर्ड का उपयोग करके इंस्टेंस बनाने की आवश्यकता नहीं होती।
डिपेंडेंसी इंजेक्शन (DI) कंटेनर की विवेचना
ASP.NET Core में डिपेंडेंसी इंजेक्शन कंटेनर (जिसे IoC कंटेनर - Inversion of Control Container भी कहा जाता है) एक रनटाइम कंपोनेंट है जो सर्विसेज़ के लाइफसाइकिल को मैनेज करता है और उनके बीच की डिपेंडेंसी को संभालता है।
यह कैसे काम करता है:
- सर्विस रजिस्ट्रेशन: आप कंटेनर को बताते हैं कि "जब भी आपको IMyService की आवश्यकता हो, तो MyServiceImplementation का उपयोग करें।"
- डिपेंडेंसी रिजॉल्यूशन: जब एक क्लास (जैसे एक कंट्रोलर) को अपने कंस्ट्रक्टर में IMyService की आवश्यकता होती है, तो कंटेनर यह पहचानता है कि उसे IMyService की आवश्यकता है। यह तब MyServiceImplementation का एक इंस्टेंस बनाता है (या पुनः उपयोग करता है, लाइफटाइम के आधार पर) और उसे कंट्रोलर के कंस्ट्रक्टर में पास करता है।
- लाइफसाइकिल प्रबंधन: कंटेनर सर्विस के लाइफटाइम (सिंगलटन, स्कोप, ट्रांजिएंट) को ट्रैक करता है और यह सुनिश्चित करता है कि उन्हें सही समय पर बनाया और डिस्पोज किया जाए।
DI कंटेनर का उपयोग करने के मुख्य लाभ हैं:
- लूज कपलिंग (Loose Coupling): कंपोनेंट्स एक-दूसरे पर सीधे निर्भर नहीं करते हैं, बल्कि इंटरफेस पर निर्भर करते हैं, जिससे कोड अधिक लचीला और बदलने में आसान हो जाता है।
- बेहतर टेस्टेबिलिटी (Testability): चूंकि डिपेंडेंसी इंजेक्ट की जाती हैं, आप आसानी से टेस्ट के दौरान मॉक या स्टब इम्प्लीमेंटेशन को इंजेक्ट कर सकते हैं, जिससे यूनिट टेस्टिंग आसान हो जाती है।
- मॉड्यूलरिटी (Modularity): कोड को छोटे, प्रबंधनीय टुकड़ों में तोड़ना आसान हो जाता है।
- पुन: प्रयोज्यता (Reusability): सर्विसेज़ को विभिन्न कंपोनेंट्स में आसानी से पुन: उपयोग किया जा सकता है।
शब्दावली स्पष्टीकरण
IServiceCollection
- परिभाषा: IServiceCollection एक इंटरफेस है जो सर्विस डिस्क्रिप्टर्स (Service Descriptors) के एक कलेक्शन का प्रतिनिधित्व करता है। यह वह जगह है जहाँ आप अपनी एप्लीकेशन की सभी सर्विसेज़ को DI कंटेनर में रजिस्टर करते हैं।
- भूमिका: यह एक बाल्टी की तरह है जहाँ आप उन सभी नियमों को फेंक देते हैं जो DI कंटेनर को बताते हैं कि कौन सी सर्विस उपलब्ध है और उसे कैसे बनाना है (उसका लाइफटाइम क्या है)।
- उपयोग: .NET 6+ में, आप इसे Services प्रॉपर्टी के माध्यम से एक्सेस करते हैं।
// Program.cs में
var builder = WebApplication.CreateBuilder(args);
// IServiceCollection के माध्यम से सर्विस रजिस्टर करना
builder.Services.AddSingleton<IMyService, MyServiceImplementation>();
builder.Services.AddScoped<IMyScopedService>();
// अगर TService और TImplementation समान हैं
builder.Services.AddTransient<IOtherService, OtherService>();
// ...var app = builder.Build();
- आप इस इंटरफेस पर विभिन्न एक्सटेंशन मेथड्स (जैसे AddSingleton, AddScoped, AddTransient, AddControllersWithViews, AddDbContext आदि) को कॉल करते हैं ताकि सर्विसेज़ को कॉन्फ़िगर और रजिस्टर किया जा सके।
IServiceProvider
- परिभाषा: IServiceProvider एक इंटरफेस है जो सर्विस को रिजॉल्व करने (resolve) या प्राप्त करने के लिए जिम्मेदार है। यह DI कंटेनर का वह हिस्सा है जो आपको रनटाइम पर रजिस्टर की गई सर्विसेज़ के इंस्टेंस प्रदान करता है।
- भूमिका: एक बार जब सभी सर्विसेज़ IServiceCollection में पंजीकृत हो जाती हैं, तो IServiceCollection को IServiceProvider में "बनाया" जाता है (आमतौर पर Build() कॉल के एक हिस्से के रूप में)। IServiceProvider तब एक फैक्ट्री की तरह कार्य करता है, जो आपको किसी विशिष्ट इंटरफ़ेस या क्लास के लिए कंक्रीट इंस्टेंस प्रदान करता है।
- उपयोग:
- NET Core स्वयं कंस्ट्रक्टर इंजेक्शन के माध्यम से सर्विसेज़ को स्वचालित रूप से इंजेक्ट करने के लिए IServiceProvider का उपयोग करता है।
- बहुत दुर्लभ मामलों में, आपको मैन्युअल रूप से IServiceProvider तक पहुँचने और एक सर्विस को "मैन्युअल रूप से रिजॉल्व" करने की आवश्यकता हो सकती है, हालांकि कंस्ट्रक्टर इंजेक्शन हमेशा पसंदीदा तरीका है।
- उदाहरण (केवल दिखावे के लिए, आमतौर पर इसकी सिफारिश नहीं की जाती है):
// किसी कंपोनेंट के अंदर (जैसे एक मिडलवेयर या कभी-कभी एक सर्विस के अंदर)
public class MyComponent
{
private readonly IServiceProvider _serviceProvider;
public MyComponent(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void DoSomething()
{
// सर्विस को मैन्युअल रूप से प्राप्त करना - बहुत ही कम उपयोग करें
var myService = _serviceProvider.GetService<IMyService>();
// या GetRequiredService अगर सर्विस के मौजूद होने की गारंटी है
var anotherService = _serviceProvider.GetRequiredService<IAnotherService>();
}
}
- IServiceProvider यह भी सुनिश्चित करता है कि जब आप GetService<T>() या GetRequiredService<T>() का उपयोग करके एक सर्विस का अनुरोध करते हैं, तो यह उस सर्विस के लिए कॉन्फ़िगर किए गए लाइफटाइम नियमों का पालन करता है (सिंगलटन, स्कोप, ट्रांजिएंट)।
संक्षेप में, IServiceCollection आपको बताता है कि क्या रजिस्टर करना है और कैसे (लाइफटाइम), जबकि IServiceProvider वह है जो वास्तव में उन रजिस्टर्ड सर्विसेज़ के इंस्टेंस को प्रदान करता है जब उनकी आवश्यकता होती है। ये दोनों मिलकर ASP.NET Core में लचीले और शक्तिशाली डिपेंडेंसी इंजेक्शन सिस्टम का निर्माण करते हैं।
एक ही सर्विस का पुनः रजिस्ट्रेशन
आये अब एक प्रश्न पर विचार करते हैं -
ASP.NET Core एप्लीकेशन के अंतर्गत यदि एक रजिस्टर किया गया है और दोबारा उसे रजिस्टर करने का प्रयास करते हैं तब क्या होता है?
यह एक बहुत ही महत्वपूर्ण और अक्सर पूछा जाने वाला सवाल है! ASP.NET Core DI कंटेनर में एक सर्विस को एक से ज़्यादा बार रजिस्टर करने पर क्या होता है, यह इस बात पर निर्भर करता है कि आपने उसे किस रजिस्ट्रेशन मेथड (जैसे AddSingleton, AddScoped, AddTransient) का उपयोग करके रजिस्टर किया है।
जब एक सर्विस को दोबारा रजिस्टर किया जाता है तो क्या होता है?
ASP.NET Core का बिल्ट-इन DI कंटेनर अंतिम रजिस्ट्रेशन (Last Registration Wins) के सिद्धांत का पालन करता है, लेकिन इसमें कुछ सूक्ष्म अंतर हैं जो सर्विस के लाइफटाइम पर निर्भर करते हैं।
1. AddSingleton<TService, TImplementation>() के साथ दोबारा रजिस्ट्रेशन
जब आप एक Singleton सर्विस को दोबारा रजिस्टर करते हैं, तो अंतिम रजिस्ट्रेशन जीत जाता है (Last Registration Wins)। इसका मतलब है कि जब सर्विस को रिजॉल्व किया जाएगा, तो DI कंटेनर उस कंक्रीट इम्प्लीमेंटेशन का इंस्टेंस प्रदान करेगा जो सबसे आखिर में रजिस्टर किया गया था।
उदाहरण:
// Program.cs में
// पहला रजिस्ट्रेशन
builder.Services.AddSingleton<IMyService, MyServiceImplementationA>();
// दूसरा रजिस्ट्रेशन (IMyService को फिर से रजिस्टर करना)
builder.Services.AddSingleton<IMyService, MyServiceImplementationB>();
// जब IMyService को रिजॉल्व किया जाएगा, तो MyServiceImplementationB का एक इंस्टेंस मिलेगा।
// MyServiceImplementationA को कभी भी इंस्टेंशिएट नहीं किया जाएगा।
परिणाम: जब आप IMyService के लिए अनुरोध करेंगे, तो आपको MyServiceImplementationB का एक सिंगलटन इंस्टेंस मिलेगा। MyServiceImplementationA वाला रजिस्ट्रेशन पूरी तरह से ओवरराइट हो जाएगा और इसका उपयोग कभी नहीं किया जाएगा।
2. AddScoped<TService, TImplementation>() के साथ दोबारा रजिस्ट्रेशन
Scoped सर्विस के मामले में भी अंतिम रजिस्ट्रेशन जीतता है (Last Registration Wins)। प्रत्येक HTTP रिक्वेस्ट के लिए, जब सर्विस का अनुरोध किया जाएगा, तो DI कंटेनर उस कंक्रीट इम्प्लीमेंटेशन का इंस्टेंस प्रदान करेगा जो सबसे आखिर में रजिस्टर किया गया था।
उदाहरण:
// Program.cs में
// पहला रजिस्ट्रेशन
builder.Services.AddScoped<IMyService, MyServiceImplementationX>();
// दूसरा रजिस्ट्रेशन
builder.Services.AddScoped<IMyService, MyServiceImplementationY>();
// जब IMyService को किसी रिक्वेस्ट के स्कोप में रिजॉल्व किया जाएगा, तो MyServiceImplementationY का एक इंस्टेंस मिलेगा।
परिणाम: जब आप IMyService के लिए अनुरोध करेंगे, तो आपको MyServiceImplementationY का एक स्कोप्ड इंस्टेंस मिलेगा। MyServiceImplementationX वाला रजिस्ट्रेशन ओवरराइट हो जाएगा।
3. AddTransient<TService, TImplementation>() के साथ दोबारा रजिस्ट्रेशन
Transient सर्विस के मामले में भी अंतिम रजिस्ट्रेशन जीतता है (Last Registration Wins)। जब भी सर्विस का अनुरोध किया जाएगा, तो DI कंटेनर उस कंक्रीट इम्प्लीमेंटेशन का एक नया इंस्टेंस प्रदान करेगा जो सबसे आखिर में रजिस्टर किया गया था।
उदाहरण:
// Program.cs में
// पहला रजिस्ट्रेशन
builder.Services.AddTransient<IMyService, MyServiceImplementationP>();
// दूसरा रजिस्ट्रेशन
builder.Services.AddTransient<IMyService, MyServiceImplementationQ>();
// जब IMyService को रिजॉल्व किया जाएगा, तो MyServiceImplementationQ का एक नया इंस्टेंस मिलेगा।
परिणाम: जब आप IMyService के लिए अनुरोध करेंगे, तो आपको MyServiceImplementationQ का एक नया ट्रांजिएंट इंस्टेंस मिलेगा। MyServiceImplementationP वाला रजिस्ट्रेशन भी ओवरराइट हो जाएगा।
लेकिन ऐसा क्यों होता है? आये अब इस प्रश्न पर विचार करते हैं -
ASP.NET Core का बिल्ट-इन DI कंटेनर अपनी IServiceCollection को एक "लिस्ट" के रूप में मानता है। जब आप एक सर्विस को रजिस्टर करते हैं, तो वह इस लिस्ट में एक ServiceDescriptor (जिसमें सर्विस टाइप, इम्प्लीमेंटेशन टाइप और लाइफटाइम की जानकारी होती है) जोड़ता है। जब आप उसी सर्विस टाइप को दोबारा रजिस्टर करते हैं, तो वह बस लिस्ट में एक और ServiceDescriptor जोड़ देता है।
जब IServiceProvider (यानी DI कंटेनर) को किसी सर्विस को रिजॉल्व करना होता है, तो वह आंतरिक रूप से इस लिस्ट के माध्यम से पीछे से आगे (यानी, सबसे हाल ही में जोड़े गए से सबसे पुराने तक) खोजता है। जैसे ही उसे वांछित सर्विस टाइप के लिए पहला मैच मिलता है, वह उसका उपयोग करता है। इसलिए, अंतिम जोड़ा गया रजिस्ट्रेशन प्रभावी हो जाता है।
इसका क्या मतलब है और कब यह मायने रखता है?
- ओवरराइटिंग: यह जानना महत्वपूर्ण है कि दोबारा रजिस्ट्रेशन मौजूदा रजिस्ट्रेशन को चुपचाप ओवरराइट कर देता है। कोई त्रुटि या चेतावनी नहीं मिलेगी, जो डिबगिंग को मुश्किल बना सकती है यदि आप गलती से एक सर्विस को दो बार रजिस्टर करते हैं और यह सोचते हैं कि पहला वाला उपयोग किया जा रहा है।
- मॉड्यूलरिटी: यह पैटर्न विशेष रूप से मॉड्यूलर एप्लीकेशनों में उपयोगी हो सकता है जहाँ विभिन्न NuGet पैकेज या एप्लीकेशन के हिस्से एक ही इंटरफ़ेस के लिए अपनी स्वयं की डिफ़ॉल्ट इम्प्लीमेंटेशन को रजिस्टर कर सकते हैं। एप्लीकेशन डेवलपर के रूप में, आप हमेशा पैकेज के बाद अपनी खुद की कस्टम इम्प्लीमेंटेशन को रजिस्टर करके उन डिफ़ॉल्ट को ओवरराइड कर सकते हैं।
- कॉन्फ़िगरेशन: आप यह सुनिश्चित करने के लिए इस व्यवहार का उपयोग कर सकते हैं कि आपके कोड में विशिष्ट कॉन्फ़िगरेशन डिफ़ॉल्ट रूप से प्रदान किए गए किसी भी पैकेज कॉन्फ़िगरेशन को ओवरराइड करते हैं।
संक्षेप में, ASP.NET Core में सर्विस का दोबारा रजिस्ट्रेशन एक नया रजिस्ट्रेशन बनाता है जो पिछले वाले को प्रभावी रूप से बदल देता है। यह एक जानबूझकर डिजाइन निर्णय है जो कॉन्फ़िगरेशन में लचीलापन प्रदान करता है, जिससे आप आसानी से डिफ़ॉल्ट सर्विस इम्प्लीमेंटेशन को ओवरराइड कर सकते हैं।
ऐसा संभव है कि जब अगली बार Same सर्विस को रजिस्टर करने का प्रयास किया जाए तब किसी प्रकार का Error मैसेज या कोई वैल्यू एप्लीकेशन को प्राप्त हो, यह बिल्कुल संभव है।
डिफ़ॉल्ट व्यवहार बनाम कस्टम व्यवहार
जैसा कि हमने पहले चर्चा की, ASP.NET Core का बिल्ट-इन DI कंटेनर डिफ़ॉल्ट रूप से "लास्ट रजिस्ट्रेशन विंस" के सिद्धांत का पालन करता है। इसका मतलब है कि यह कोई एरर या चेतावनी नहीं देता है, बस पुराना रजिस्ट्रेशन नए से ओवरराइट हो जाता है। यह एक डिज़ाइन निर्णय है जो लचीलापन प्रदान करता है (उदाहरण के लिए, थर्ड-पार्टी लाइब्रेरी के डिफ़ॉल्ट को ओवरराइड करना)।
हालांकि, अगर आपकी एप्लीकेशन की आवश्यकता है कि एक ही सर्विस को दो बार रजिस्टर करने पर एक समस्या मानी जाए (और आप ऐसा होने से रोकना चाहते हैं), तो आप इसे निम्न तरीकों से प्राप्त कर सकते हैं:
1. मैन्युअल चेक और कस्टम एक्सटेंशन मेथड बनाना
आप IServiceCollection के लिए एक कस्टम एक्सटेंशन मेथड बना सकते हैं जो सर्विस रजिस्टर करने से पहले यह जांचे कि क्या सर्विस पहले से ही पंजीकृत है। यदि ऐसा है, तो यह एक InvalidOperationException फेंक सकता है या एक बूलियन मान लौटा सकता है।
उदाहरण:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
// TryAddSingleton, TryAddScoped, TryAddTransient के लिए
public static class ServiceCollectionExtensions
{
// एक नया कस्टम रजिस्ट्रेशन मेथड जो चेक करता है
public static IServiceCollection AddSingletonUnique<TService, TImplementation>(this IServiceCollection services) where TService : class where TImplementation : class, TService
{
// चेक करें कि क्या TService पहले से ही पंजीकृत है
if (services.Any(s => s.ServiceType == typeof(TService)))
{
throw new InvalidOperationException($"Service of type {typeof(TService).FullName} is already registered. Duplicate registration not allowed.");
}
services.AddSingleton<TService, TImplementation>();
return services;
}
// आप AddScopedUnique और AddTransientUnique भी बना सकते हैं}
// Program.cs में इसका उपयोग कैसे करेंvar builder = WebApplication.CreateBuilder(args);
// यह ठीक काम करेगाbuilder.Services.AddSingletonUnique<IMyService, MyServiceImplementationA>();
// यह एक InvalidOperationException फेंकेगा
// builder.Services.AddSingletonUnique<IMyService, MyServiceImplementationB>();
var app = builder.Build();
// ...app.Run();
}
फायदे:
- यह आपको पूरी तरह से नियंत्रण देता है कि आप कैसे एरर हैंडलिंग करना चाहते हैं।
- यह स्पष्ट रूप से बताता है कि आपका इरादा डुप्लिकेट रजिस्ट्रेशन को रोकना है।
नुकसान:
- आपको हर उस रजिस्ट्रेशन मेथड के लिए कस्टम एक्सटेंशन मेथड बनाना होगा जिसे आप नियंत्रित करना चाहते हैं (AddSingletonUnique, AddScopedUnique, AddTransientUnique आदि)।
- यह बिल्ट-इन मेथड्स को बदलने के लिए अतिरिक्त कोड है।
2. TryAdd* एक्सटेंशन मेथड्स का उपयोग करना
Microsoft ने Microsoft.Extensions.DependencyInjection.Extensions नेमस्पेस में कुछ उपयोगी एक्सटेंशन मेथड्स प्रदान किए हैं, जैसे TryAddSingleton(), TryAddScoped(), और TryAddTransient()। ये मेथड्स केवल तभी सर्विस को रजिस्टर करते हैं जब वह सर्विस टाइप अभी तक पंजीकृत न हो। यदि सर्विस पहले से ही पंजीकृत है, तो ये मेथड्स कुछ नहीं करते हैं और कोई एरर भी नहीं फेंकते हैं।
उदाहरण:
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.DependencyInjection.Extensions;
// TryAdd* मेथड्स के लिए
// Program.cs में
var builder = WebApplication.CreateBuilder(args);
// यह सफलतापूर्वक रजिस्टर होगा
builder.Services.TryAddSingleton<IMyService, MyServiceImplementationA>();Console.WriteLine("IMyService (A) registered successfully.");
// यह कुछ नहीं करेगा क्योंकि IMyService पहले से ही पंजीकृत है। कोई एरर नहीं।
builder.Services.TryAddSingleton<IMyService, MyServiceImplementationB>();
Console.WriteLine("IMyService (B) attempted, but likely not registered.");
var app =
builder.Build();
// टेस्ट करने के लिए
app.MapGet("/myservice", (IMyService myService) => myService.GetType().Name);
app.Run();
// आउटपुट: MyServiceImplementationA (क्योंकि B रजिस्टर नहीं हुआ)
फायदे:
- यह एक क्लीनर और बिल्ट-इन तरीका है यह सुनिश्चित करने का कि एक सर्विस केवल एक बार ही पंजीकृत हो।
- कोई अपवाद नहीं फेंका जाता है, जो कुछ परिदृश्यों में वांछनीय हो सकता है।
नुकसान:
- यह कोई एरर या चेतावनी नहीं देता है, जिसका अर्थ है कि अगर आपको उम्मीद थी कि दूसरा रजिस्ट्रेशन प्रभावी होगा, तो आपको पता नहीं चलेगा कि ऐसा नहीं हुआ है। आपको यह सुनिश्चित करने के लिए लॉगिंग या अन्य निरीक्षण करने की आवश्यकता होगी कि कौन सा इम्प्लीमेंटेशन वास्तव में उपयोग किया जा रहा है।
- यह "लास्ट रजिस्ट्रेशन विंस" व्यवहार को बदलता है, जिसे कभी-कभी मॉड्यूलरिटी के लिए वांछित किया जाता है।
3. कस्टम DI कंटेनर का उपयोग करना (एडवांस्ड)
ASP.NET Core एक प्लगगेबल DI कंटेनर आर्किटेक्चर का समर्थन करता है। इसका मतलब है कि आप Microsoft के बिल्ट-इन कंटेनर को बदलकर तीसरे पक्ष के DI कंटेनर जैसे Autofac, DryIoc, Ninject आदि का उपयोग कर सकते हैं। इनमें से कई कंटेनर डुप्लिकेट रजिस्ट्रेशन को संभालने के लिए विभिन्न कॉन्फ़िगरेशन विकल्प प्रदान करते हैं, जिनमें डुप्लिकेट होने पर एरर फेंकना भी शामिल है।
फायदे:
- अधिक शक्तिशाली और कॉन्फ़िगरेबल DI क्षमताएं।
- कुछ कंटेनर अधिक उन्नत फीचर्स (जैसे इंटरसेप्शन, ऑटो-रजिस्ट्रेशन) प्रदान करते हैं।
नुकसान:
- आपके प्रोजेक्ट में एक अतिरिक्त निर्भरता (NuGet पैकेज) जुड़ जाती है।
- सीखने की अवस्था (learning curve) हो सकती है क्योंकि प्रत्येक कंटेनर की अपनी API और कॉन्फ़िगरेशन होती है।
- डिफ़ॉल्ट NET Core DI कंटेनर आमतौर पर अधिकांश एप्लीकेशनों के लिए पर्याप्त होता है।
टिप्पणियाँ
एक टिप्पणी भेजें